/**
 * @file Singleton.h
 * @brief To-be-added
 * @copyright Copyright (c) 2020 YUSUR Technology Co., Ltd. All Rights Reserved. Learn more at
 * www.yusur.tech.
 * @author TianXing Qu (qutx@yusur.tech)
 * @date 2022-03-10 11:36:59
 * @last_author: TianXing Qu (qutx@yusur.tech)
 * @last_edit_time: 2022-11-18 11:11:05
 */
#ifndef _BASE_SINGLETON_H_
#define _BASE_SINGLETON_H_

#include "noncopyable.h"
#include <assert.h>
#include <stdlib.h>
#include <thread>
#include <mutex>

namespace yusur
{

// This doesn't detect inherited member functions!
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
template <typename T>
struct has_no_destroy
{
    template <typename C>
    static char test(decltype(&C::no_destroy));
    template <typename C>
    static int        test(...);
    const static bool value = sizeof(test<T>(0)) == 1;
};

template <typename T>
class Singleton : NonCopyable
{
public:
    Singleton(/* args */) = default;
    ~Singleton()          = default;

    static T& get_instance()
    {
        std::call_once(ponce_, &Singleton::init);
        assert(value_ != NULL);
        return *value_;
    }

private:
    static void init()
    {
        value_ = new T();
        if (!yusur::has_no_destroy<T>::value)
        {
            std::atexit(destroy);
        }
    }

    static void destroy()
    {
        typedef char            T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
        T_must_be_complete_type dummy;
        (void)dummy;

        delete value_;
        value_ = NULL;
    }

private:
    static std::once_flag ponce_;
    static T*             value_;
};
template <typename T>
std::once_flag Singleton<T>::ponce_;

template <typename T>
T* Singleton<T>::value_ = NULL;
}  // namespace yusur
#endif  //_BASE_SINGLETON_H_
